import { appendFileSync, existsSync, mkdirSync, readdirSync, renameSync, statSync, unlinkSync } from 'node:fs'
import { dirname } from 'node:path'
import { join } from 'node:path'

export interface AuditRecord {
  ts: string
  plugin: string
  method: string
  allowed: boolean
  resource?: any
  error?: { code: number; message: string; data?: any }
}

export interface AuditFilesConfig {
  dataDir: string
  fileName?: string // default: audit.log
  maxBytes?: number // default: 5MB
  keep?: number // default: 5 rotated files
}

export function getAuditFilePath(cfg: AuditFilesConfig) {
  return join(cfg.dataDir, cfg.fileName || 'audit.log')
}

export function rotateAuditIfNeeded(cfg: AuditFilesConfig) {
  const auditFile = getAuditFilePath(cfg)
  try {
    if (!existsSync(auditFile)) return
    const { size } = statSync(auditFile)
    const limit = Number(cfg.maxBytes || 5_000_000)
    if (size < limit) return
    const ts = new Date().toISOString().replace(/[:.]/g, '-')
    const rotated = auditFile.replace(/\.log$/, `.${ts}.log`)
    renameSync(auditFile, rotated)
    const dir = dirname(auditFile)
    const base = auditFile.split('/').pop()!.replace(/\.log$/, '')
    const files = readdirSync(dir)
      .filter((f) => f.startsWith(base + '.') && f.endsWith('.log'))
      .sort()
    const keep = Math.max(1, Number(cfg.keep || 5))
    while (files.length > keep) {
      const f = files.shift()!
      try { unlinkSync(join(dir, f)) } catch {}
    }
  } catch {}
}

export function appendAudit(cfg: AuditFilesConfig, rec: AuditRecord) {
  const auditFile = getAuditFilePath(cfg)
  const line = JSON.stringify(rec) + '\n'
  mkdirSync(cfg.dataDir, { recursive: true })
  rotateAuditIfNeeded(cfg)
  appendFileSync(auditFile, line)
}

